package com.starsky.common.utils;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.Map.Entry;

/**
 * HttpUtils工具
 */
public class HttpUtils {
    private static CloseableHttpClient httpClient;
    private static final String ENCODEING = "UTF-8";
    private static final int CONNECTION_TIMEOUT = 60000;
    private static Logger log = LoggerFactory.getLogger(HttpUtils.class);

    public static String doGet(String url, Map<String, Object> headers, Map<String, Object> params) {
        String result = null;
        HttpGet httpGet = null;
        try {
            StringBuffer param;
            if (params != null) {
                param = new StringBuffer();
                for (String key : params.keySet()) {
                    if (param.length() == 0) {
                        param.append("?");
                    } else {
                        param.append("&");
                    }
                    param.append(key).append("=").append(URLEncoder.encode(params.get(key).toString(), "UTF-8"));
                }
                url = url + param;
            }

            httpGet = new HttpGet(url);

            if (headers != null) {
                for (String key : headers.keySet()) {
                    httpGet.setHeader(key, headers.get(key).toString());
                }
            } else {
                httpGet.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
                httpGet.setHeader("Accept", "application/json");
            }

            HttpResponse response = httpClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();

            if (statusCode == 200) {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    result = EntityUtils.toString(entity, "UTF-8");
                }
            }
        } catch (IOException e) {
            log.error("HttpClient: doGet error.url=" + url + ",headers=" + headers + ",params=" + params, e);
        } finally {
            if (httpGet != null) {
                httpGet.releaseConnection();
            }
        }

        return result;
    }

    public static byte[] doGetForBytes(String url, Map<String, Object> headers, Map<String, Object> params) {
        byte[] result = null;
        HttpGet httpGet = null;
        try {
            StringBuffer param;
            if (params != null) {
                param = new StringBuffer();
                for (String key : params.keySet()) {
                    if (param.length() == 0) {
                        param.append("?");
                    } else {
                        param.append("&");
                    }
                    param.append(key).append("=").append(URLEncoder.encode(params.get(key).toString(), "UTF-8"));
                }
                url = url + param;
            }

            httpGet = new HttpGet(url);

            if (headers != null) {
                for (String key : headers.keySet()) {
                    httpGet.setHeader(key, headers.get(key).toString());
                }
            } else {
                httpGet.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
                httpGet.setHeader("Accept", "application/json");
            }

            HttpResponse response = httpClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();

            if (statusCode == 200) {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    result = EntityUtils.toByteArray(entity);
                }
            }
        } catch (IOException e) {
            log.error("HttpClient: doGet error.url=" + url + ",headers=" + headers + ",params=" + params, e);
        } finally {
            if (httpGet != null) {
                httpGet.releaseConnection();
            }
        }

        return result;
    }

    public static String doPost(String url, Map<String, Object> headers, Map<String, Object> params) {
        try {
            HttpEntity entity = null;
            if (params != null) {
                List pairList = new ArrayList();
                for (Entry entry : params.entrySet()) {
                    String value = "";
                    if (entry.getValue() != null) {
                        value = entry.getValue() + "";
                    }
                    NameValuePair pair = new BasicNameValuePair((String) entry.getKey(), value);
                    pairList.add(pair);
                }
                entity = new UrlEncodedFormEntity(pairList, "UTF-8");
            }
            return doPost(url, headers, entity);
        } catch (Exception e) {
            log.error("HttpClient: doPost error.url=" + url + ",headers=" + headers + ",params=" + params, e);
        }
        return null;
    }

    public static String doPost(String url, Map<String, Object> headers, String str) {
        try {
            HttpEntity entity = null;
            if (StringUtils.isNotBlank(str)) {
                entity = new StringEntity(str.toString(), "UTF-8");
            }
            return doPost(url, headers, entity);
        } catch (Exception e) {
            log.error("HttpClient: doPost error.url=" + url + ",headers=" + headers + ",str=" + str, e);
        }
        return null;
    }

    private static String doPost(String url, Map<String, Object> headers, HttpEntity requestEntity)
            throws Exception {
        HttpPost httpPost = new HttpPost(url);
        try {
            if (requestEntity != null) {
                httpPost.setEntity(requestEntity);
            }

            if (headers != null) {
                for (String key : headers.keySet()) {
                    httpPost.setHeader(key, headers.get(key).toString());
                }
            } else {
                httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
                httpPost.setHeader("Accept", "application/json");
            }
            HttpResponse response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                HttpEntity entity = ((HttpResponse) response).getEntity();
                if (entity != null) {
                    String str1 = EntityUtils.toString(entity, "UTF-8");
                    return str1;
                }
            } else {
                log.error("HttpClient: doPost error.statusCode=" + statusCode + "url=" + url + ",headers=" + headers + ",requestEntity=" + requestEntity);
            }
        } finally {
            httpPost.releaseConnection();
        }

        return null;
    }

    private static SSLConnectionSocketFactory createSSLConnSocketFactory() {
        SSLConnectionSocketFactory sslsf = null;
        try {
            SSLContext ctx = SSLContext.getInstance("TLS");

            X509TrustManager tm = new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
            ctx.init(null, new TrustManager[]{tm}, null);
            sslsf = new SSLConnectionSocketFactory(ctx, NoopHostnameVerifier.INSTANCE);
        } catch (Exception e) {
            log.error("HttpClient: create SSL socket factory error.", e);
        }

        return sslsf;
    }

    static {
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(CONNECTION_TIMEOUT)
                .setSocketTimeout(CONNECTION_TIMEOUT)
                .setConnectionRequestTimeout(CONNECTION_TIMEOUT)
                .setAuthenticationEnabled(true)
                .setExpectContinueEnabled(true)
                .setTargetPreferredAuthSchemes(Arrays.asList("NTLM", "Digest"))
                .setProxyPreferredAuthSchemes(Arrays.asList("Basic"))
                .build();

        Registry socketFactoryRegistry = RegistryBuilder.create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https",
                        createSSLConnSocketFactory()).build();

        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        connManager.setMaxTotal(800);
        connManager.setDefaultMaxPerRoute(800);

        httpClient = HttpClients.custom().setConnectionManager(connManager).setDefaultRequestConfig(requestConfig)
                .build();
    }

    /**
     * 基于HttpClient 4.3的通用POST方法
     *
     * @param url       提交的URL
     * @param paramsMap 提交<参数，值>Map
     * @return 提交响应
     */
    public static String dopost(String url, Map<String, String> paramsMap) {
        CloseableHttpClient client = HttpClients.createDefault();
        String responseText = "";
        CloseableHttpResponse response = null;
        try {
            HttpPost method = new HttpPost(url);
            if (paramsMap != null) {
                List<NameValuePair> paramList = new ArrayList<>();
                for (Entry<String, String> param : paramsMap.entrySet()) {
                    NameValuePair pair = new BasicNameValuePair(param.getKey(), param.getValue());
                    paramList.add(pair);
                }
                method.setEntity(new UrlEncodedFormEntity(paramList, ENCODEING));
            }
            response = client.execute(method);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                responseText = EntityUtils.toString(entity, ENCODEING);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return responseText;
    }


    /**
     * 获取请求Body
     *
     * @param request
     * @return
     */
    public static String getBodyString(ServletRequest request) {
        StringBuilder sb = new StringBuilder();
        InputStream inputStream = null;
        BufferedReader reader = null;
        try {
            inputStream = request.getInputStream();
            reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }

    /**
     * 描述:获取 request 中请求的内容
     *
     * <pre>
     * 举例：
     * </pre>
     *
     * @param request
     * @return
     * @throws IOException
     */
    public static String getRequestQuery(HttpServletRequest request) throws IOException {
        String submitMehtod = request.getMethod();
        // GET
        if (submitMehtod.equals("GET")) {
            return new String(request.getQueryString().getBytes("iso-8859-1"), "utf-8");
            // POST
        }
        else {
            return getRequestPostStr(request);
        }
    }

    /***
     * 获取 request 中 json 字符串的内容
     *
     * @param request
     * @return : <code>byte[]</code>
     * @throws IOException
     */
    public static String getRequestJson(HttpServletRequest request) throws IOException {
        String submitMehtod = request.getMethod();
        // GET
        if (submitMehtod.equals("GET")) {
            return new String(request.getQueryString().getBytes("iso-8859-1"), "utf-8").replaceAll("%22", "\"");
            // POST
        }
        else {
            return getRequestPostStr(request);
        }
    }

    /**
     * 描述:获取 post 请求的 byte[] 数组
     *
     * <pre>
     * 举例：
     * </pre>
     *
     * @param request
     * @return
     * @throws IOException
     */
    public static byte[] getRequestPostBytes(HttpServletRequest request) throws IOException {
        int contentLength = request.getContentLength();
        if (contentLength < 0) {
            return null;
        }
        byte buffer[] = new byte[contentLength];
        for (int i = 0; i < contentLength;) {

            int readlen = request.getInputStream().read(buffer, i, contentLength - i);
            if (readlen == -1) {
                break;
            }
            i += readlen;
        }
        return buffer;
    }

    /**
     * 描述:获取 post 请求内容
     *
     * <pre>
     * 举例：
     * </pre>
     *
     * @param request
     * @return
     * @throws IOException
     */
    public static String getRequestPostStr(HttpServletRequest request) throws IOException {
        byte buffer[] = getRequestPostBytes(request);
        String charEncoding = request.getCharacterEncoding();
        if (charEncoding == null) {
            charEncoding = "UTF-8";
        }
        return new String(buffer, charEncoding);
    }


    /**
     * post方式访问网络资源
     *
     * @param url:网络资源链接
     * @param params     参数
     * @version ; 1.0
     */
    public static String post(String url, Map<String, String> params) {
        // 默认的client类。
        DefaultHttpClient httpclient = new DefaultHttpClient();
        HttpPost post = postForm(url, params);
        String body = invoke(httpclient, post);
        // 关闭连接.
        httpclient.getConnectionManager().shutdown();
        return body;
    }

    /**
     * get方式访问网络资源
     *
     * @param url
     * @return
     * @version ; 1.0
     */
    public static String get(String url) {
        DefaultHttpClient httpclient = new DefaultHttpClient();
        // 设置为get取连接的方式.
        HttpGet get = new HttpGet(url);
        String body = invoke(httpclient, get);
        // 关闭连接.
        httpclient.getConnectionManager().shutdown();
        return body;
    }


    private static String invoke(DefaultHttpClient httpclient,
                                 HttpUriRequest httpost) {
        HttpResponse response = sendRequest(httpclient, httpost);
        String body = paseResponse(response);
        return body;
    }

    private static String paseResponse(HttpResponse response) {
        //获取本地信息
        HttpEntity entity = response.getEntity();
        String charset = EntityUtils.getContentCharSet(entity);
        String body = null;
        try {
            body = EntityUtils.toString(entity);
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return body;
    }

    /**
     * 传递本地的http上下文给服务器
     *
     * @param httpclient
     * @param httpost
     * @return
     */
    private static HttpResponse sendRequest(DefaultHttpClient httpclient,
                                            HttpUriRequest httpost) {
        HttpResponse response = null;
        try {
            //传递本地的http上下文给服务器
            response = httpclient.execute(httpost);
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return response;
    }

    private static HttpPost postForm(String url, Map<String, String> params) {
        // 设置为Post取连接的方式.
        HttpPost httpost = new HttpPost(url);
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        Set<String> keySet = params.keySet();
        for (String key : keySet) {
            nvps.add(new BasicNameValuePair(key, params.get(key)));
        }
        try {
            // 设置请求的编码格式
            httpost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return httpost;
    }


    public static String get(String url, String chartset) {

        if (StringUtils.isEmpty(chartset)) {
            chartset = "UTF-8";
        }
        StringBuffer content = new StringBuffer();
        HttpURLConnection httpConn = null;
        BufferedReader in = null;
        try {
            URL url1 = new URL(url);
            httpConn = (HttpURLConnection) url1.openConnection();
            // 读取响应
            if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                String tempStr = "";
                in = new BufferedReader(new InputStreamReader(httpConn.getInputStream(), chartset));
                while ((tempStr = in.readLine()) != null) {
                    content.append(tempStr);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (httpConn != null) {
                httpConn.disconnect();
            }
        }
        return content.toString();
    }


    /**
     * 发送post请求
     *
     * @param url 请求url
     * @param json json数据
     * @return
     */
    private static String sendPost(String url, String json) {

        StringEntity entity = new StringEntity(json, "UTF-8");
        entity.setContentType("Content-Type");

        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("Content-Type", "application/json;charset=UTF-8");
        httpPost.setEntity(entity);

        HttpEntity entity2 = null;
        try {
            HttpClient client = HttpClientBuilder.create().build();
            HttpResponse response2 = client.execute(httpPost);
            entity2 = response2.getEntity();
        } catch (Exception var12) {
            log.error("ws send2ws =======================IOException" + var12);
            var12.printStackTrace();
        }

        String s2 = null;
        try {
            s2 = EntityUtils.toString(entity2, "UTF-8");
        } catch (Exception var10) {
            log.error("ws send2ws =======================IOException88" + var10);
            var10.printStackTrace();
        }

        return s2;
    }


}
